const MsgCode = require('./../define/MsgCode');
const RoomState = require('./../define/RoomState');

module.exports = class Room {
    /**
     * 构造函数
     * @param {Object} app
     * @param {Object} options
     * */
    constructor (app, options) {
        console.log('options: ', options);
        this._app = app;
        this._channelService = this._app.get('channelService');
        this._class_name = 'Room';
        this._room_state = RoomState.Created;
        this._current_round = 0;
        this._total_round = 4;
        this._room_id = options.room_id;
        this._house_owner_uid = '';
        this._is_allow_watchers = false; // 是否允许观看

        this._players = [];  // 游戏玩家
        this._watchers = []; // 观看者
        this._uid2info = {}; // uid转玩家信息

        this._max_players = 5; // 最大玩家数
        this._pos2uid = {};    // 位置表

        this._turn_uids = [];     // 可以发牌的玩家和操作的玩家
        this._rounds_data = {};   // 每一轮的数据
        this._uid2totalscore = {};// 玩家累计分数

        this._total_time = 10;  // 总的操作时间
        this._residue_time = 10;// 剩余的操作时间

        this._banker_uid = ''; // 庄家uid

        // 以下是初始化
        for (let i = 0; i < this._max_players; i++) {
            this._pos2uid[i] = '';
        }
    }

    /**
     * 发送消息
     * @param {Number} code   消息号
     * @param {Object} [data] 数据体
     * @param {Array | String | Number} [uids]  默认群发
     * @protected
     * */
    send (code, data, uids) {
        if (typeof data === 'undefined') {
            data = {};
        }
        if (typeof uids === 'undefined') {
            uids = Object.keys(this._uid2info);
        }
        if (!Array.isArray(uids)) {
            uids = [uids];
        }
        let msg = {};
        msg.code = code;
        msg.data = data;
        msg.data.room_id = this._room_id;

        console.info('Room send uids: ', uids, ' | room_id: ', this._room_id);

        let receiver_list = [];
        for (let i = 0; i < uids.length; i++) {
            let channel = this._channelService.getChannel(this._room_id, false);
            let member = channel.getMember(uids[i]);
            if (member) {
                let obj = {};
                obj.uid = uids[i];
                obj.sid = member['sid'];
                receiver_list.push(obj);
            }
        }
        this._channelService.pushMessageByUids('onNotify', msg, receiver_list, null, null);
    }

    /**
     * 获得一个可用的位置号
     * @param {String | Number} uid
     * @return {Number}
     * @protected
     * */
    getPos (uid) {
        let p = -1;
        for (let pos in this._pos2uid) {
            if (this._pos2uid.hasOwnProperty(pos) && this._pos2uid[pos] === '') {
                this._pos2uid[pos] = uid;
                p = pos;
                break;
            }
        }
        return parseInt(p);
    }

    /**
     * 回收位置号
     * @param {Number} pos
     * @protected
     * */
    resetPos (pos) {
        console.info('重置位置号【' + pos + '】');
        if (this._pos2uid.hasOwnProperty(pos)) {
            this._pos2uid[pos] = '';
        }
    }

    /**
     * 判断该玩家是否在房间内（断线续玩就在房间内）
     * @param {String} uid 玩家uid
     * @public
     * */
    exist (uid) {
        return this._uid2info.hasOwnProperty(uid);
    }

    /**
     * 添加玩家
     * @param {Object} info
     * @return {Boolean}
     * @public
     * */
    addPlayer (info) {
        // 1、先判断是否是断线续玩
        if (this._uid2info.hasOwnProperty(info.uid)) {
            this._uid2info[info.uid].is_online = true;
            let uids = this._getAllUidExclude(info.uid);
            if (uids && uids.length > 0) {
                // 广播玩家掉线
                // this.send(MsgCode.LeaveRoom, {
                //     uid: info.uid,
                //     msg: '玩家上线了'
                // });
                this.login(info.uid);
            }
            console.log('房间【' + this._room_id + '】中玩家【' + info.uid + '】上线了...');
            return true;
        }

        // 2、加入房间的逻辑
        if (this._players.length < this._max_players) {
            let pos = this.getPos(info.uid);
            if (pos > -1) {
                info.pos = pos;
                info.is_ready = false;
                info.is_online = true;
                info.house_owner = false;
                info.is_watchers = false;
                this._players.push(info);
                this._uid2info[info.uid] = info;
                if (!info.is_ready) {
                    this._prepare(info.uid);
                }
                if (this._players.length === 1) {
                    this._house_owner_uid = info.uid;
                }
                return true;
            } else {
                console.debug('添加玩家时分配位置号出错啦！最大玩家数【' + this._max_players + '】已有玩家数【' + this._players.length + '】');
                console.debug('位置表：' + this._pos2uid);
                return false;
            }
        }
        return this.addWatcher(info);
    }

    /**
     * 删除玩家
     * @param {String | Number} uid
     * @return {Boolean}
     * @public
     * */
    removePlayer (uid) {
        if (typeof uid === 'undefined' || !uid) {
            console.debug('删除玩家时，uid为空');
            return false;
        }

        // 广播所有人知晓这个玩家退出了
        let data = {
            uid: uid
        };
        this.send(MsgCode.LeaveRoom, data);

        // 从玩家列表剔除
        let index = -1;
        for (let i = 0; i < this._players.length; i++) {
            if (this._players[i].uid === uid) {
                index = i;
                break;
            }
        }
        if (index > -1) {
            let info_array = this._players.splice(index, 1);
            if (info_array.length > 0) {
                let info = info_array.shift();
                this.resetPos(info.pos);
                // console.info('删除玩家的信息：', info);
            }
        }

        // 清除玩家信息
        if (this._uid2info.hasOwnProperty(uid)) {
            delete this._uid2info[uid];
        }

        console.log('玩家【' + uid + '】退出房间【' + this._room_id + '】剩余玩家【' + Object.keys(this._uid2info).toString() + '】');
        console.log('_uid2info:', this._uid2info);
        console.log('_players.length:', this._players.length);
        console.log('_pos2uid:', this._pos2uid);
        return true;
    }

    /**
     * 玩家登录游戏
     * */
    login (uid) {
        if (typeof uid === 'undefined' || !uid) {
            console.debug('玩家登录游戏时，uid为空');
            return false;
        }
        if (this._uid2info.hasOwnProperty(uid)) {
            this._uid2info[uid].is_online = true;
        }
        let uids = this._getAllUidExclude(uid);
        if (uids && uids.length > 0) {
            // 广播玩家上线
            this.send(MsgCode.OnlineStatus, {
                uid: uid,
                is_online: true,
                msg: '玩家上线了'
            });
        }
        console.log('房间【' + this._room_id + '】中玩家【' + uid + '】上线了...');
    }

    /**
     * 用户注销处理
     * @param {String} uid
     * @public
     * */
    logout (uid) {
        if (typeof uid === 'undefined' || !uid) {
            console.debug('用户注销处理时，uid为空');
            return false;
        }

        if (this._uid2info.hasOwnProperty(uid)) {
            this._uid2info[uid].is_online = false;
        }
        let uids = this._getAllUidExclude(uid);
        if (uids && uids.length > 0) {
            // 广播玩家掉线
            this.send(MsgCode.OnlineStatus, {
                uid: uid,
                is_online: false,
                msg: '玩家离线了'
            });
        }
        console.log('房间【' + this._room_id + '】中玩家【' + uid + '】掉线了...');
    }

    /**
     * 获得所有的游戏玩家
     * @return {Array}
     * @public
     * */
    getPlayers () {
        return this._players;
    }

    /**
     * 获得房间配置项
     * @return {Object}
     * @public
     * */
    getOpstions () {
        return this._options;
    }

    /**
     * 是否可以观看
     * @return {Boolean}
     * */
    isAllowWatcher () {
        return this._is_allow_watchers;
    }

    /**
     * 开始游戏，生成可以发牌和可操作玩家的uids数组
     * @protected
     * */
    _onStartGame () {
        this._room_state = RoomState.Playing;
        this._current_round++;
        this._turn_uids = [];
        for (let i = 0; i < this._players.length; i++) {
            this._turn_uids.push(this._players[i].uid);
        }
        this.send(MsgCode.StartGame);
    }

    /**
     * 发牌
     * @protected
     * */
    _dealCards () {}

    /**
     * 获得庄家uid
     * @return {String | Number}
     * @protected
     * */
    _getBanker () {
        return this._banker_uid;
    }

    /**
     * 是否是庄家
     * @param {String} uid
     * @protected
     * */
    _isBanker (uid) {
        return this._getBanker() === uid;
    }

    /**
     * 正在游戏排除指定uid之外的所有uid
     * @param {String} uid 排除uid
     * @return {Array}
     * @protected
     * */
    _getAllUidExclude (uid) {
        let uids = [];
        if (this._is_allow_watchers) {
            uids = Object.keys(this._uid2info);
        } else {
            for (let i = 0; i < this._players.length; i++) {
                uids.push(this._players[i].uid);
            }
        }
        let index = uids.indexOf(uid);
        if (index > -1) {
            uids.splice(index, 1);
        }
        return uids;
    };

    /**
     * 添加观看者
     * @param {Object} info
     * @return {Boolean}
     * @public
     * */
    addWatcher (info) {
        info.pos = -1;
        info.is_ready = false;
        info.is_online = true;
        info.house_owner = false;
        info.is_watchers = true;
        this._watchers.push(info);
        return true;
    }

    /**
     * 移除观看者
     * @param {String | Number} uid
     * @return {Boolean}
     * @public
     * */
    removeWatcher (uid) {
        let index = -1;
        for (let i = 0; i < this._watchers.length; i++) {
            if (this._watchers[i].uid === uid) {
                index = i;
                break;
            }
        }
        if (index > -1) {
            let info = this._watchers.splice(index, 1);
            if (this._uid2info.hasOwnProperty(info.uid)) {
                this.resetPos(info.pos);
                delete this._uid2info[uid];
                this._uid2info[uid] = null;
                return true;
            }
        }
        return false;
    }

    /**
     * 是否可以离开房间
     * @return {Boolean}
     * @public
     * */
    canLeaveRoom () {
        return this._room_state !== RoomState.Playing;
    }

    /**
     * 是否可以销毁该房间
     * @return {Boolean} 是否可以摧毁
     * @public
     * */
    canDestroy () {
        return this._players.length === 0;
    };

    /**
     * 是否是最后一局
     * @return {Boolean}
     * @protected
     * */
    isLastRound () {
        return this._current_round >= this._total_round;
    }

    /**
     * 消息处理
     * @param {Object} msg
     * @public
     * */
    onNotify (msg) {
        let code = msg['code'];
        let data = msg['data'];
        switch (code) {
            case MsgCode.Chat:
                this._onChat(data);
                break;
            case MsgCode.StartGame:
                this._onStartGame();
                break;
            case MsgCode.Prepare:
                this._onPrepare(data);
                break;
            case MsgCode.OnTurn:
                this._onTurn(data);
                break;
            default:
                break;
        }
    }

    /**
     * 广播玩家该准备了，显示准备按钮
     * @param {String} [uid]
     * @protected
     * */
    _prepare (uid) {
        this._room_state = RoomState.Prepare;
        let data = {
            room_state: this._room_state,
            preapre: true
        };
        if (typeof uid === 'undefined') {
            this.send(MsgCode.ShowButtons, data);
        } else {
            this.send(MsgCode.ShowButtons, data, uid);
        }
    }

    /**
     * 广播准备消息
     * @param {Object} data
     * @protected
     * */
    _onPrepare (data) {
        let uid = data.uid;
        let is_ready = data.is_ready;
        if (typeof is_ready === 'undefined') {
            is_ready = true;
        }
        if (this._uid2info.hasOwnProperty(uid)) {
            this._uid2info[uid].is_ready = is_ready;
            let data = {
                uid: uid,
                is_ready: this._uid2info[uid].is_ready,
                msg: '广播准备状态'
            };
            this.send(MsgCode.Prepare, data);
        }

        // 所有人准备好了，发送显示准备按钮
        let is_all_ready = true;
        for (let i = 0; i < this._players.length; i++) {
            if (!this._players[i].is_ready) {
                is_all_ready = false;
                break;
            }
        }
        if (is_all_ready && this._players.length > 1) {
            this.send(MsgCode.ShowButtons, {
                startgame: true,
                house_owner_uid: this._house_owner_uid
            });
        }

    }

    /**
     * 操作
     * @protected
     * */
    _turn () {}

    /**
     * 处理操作
     * @param {Object} data
     * @protected
     * */
    _onTurn (data) {}

    /**
     * 聊天（暂时处理是直接群发）
     * @param {Object} data
     * @protected
     * */
    _onChat (data) {
        this.send(MsgCode.Chat, data);
    }

    /**
     * 玩家离开房间
     * @param {Object} data
     * */
    _onLeave (data) {
        let uid = data.uid;
        let room_id = data.room_id;
        console.info('玩家【' + uid + '】离开房间【' + room_id + '】');
    }

    /**
     * 结算
     * @protected
     * */
    _settlement () {
        this._room_state = RoomState.Settlement;
        for (let i = 0; i < this._players.length; i++) {
            this._players[i].is_ready = false;
        }
    }

    /**
     * 总结算
     * @protected
     * */
    _totalSettlement () {
        this._room_state = RoomState.TotalSettlement;
    }
};